﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ESF.MUP.BasePlatform.Configuration
{

    public enum ConnectorStatus
    {
        Discovered,
        MissingConfigurationFile,
        MissingConnectorName,
        MissingMainAssemblyName,
        MissingMainAssemblyFile,
        MissingStrongName,
        AssemblyLoadFailure,
        AssemblyLoaded,
        TypeUnknwon,
        TypeResolved,
        ConnectorPathInavlid,
        UnknownError,
        PermissionDenied
    }

    public class ConnectorConfiguration
    {
        public const String CONFIGURATION_FILE = "connector.config";

        /// <summary>
        /// Get the Connector name
        /// </summary>
        public String Name { get; private set; }

        /// <summary>
        /// Get the Main Assemby dll name
        /// </summary>
        public String MainAssembly { get; private set; }

        /// <summary>
        /// Get the Strong name of the manager
        /// </summary>
        public String StrongName { get; private set; }

        /// <summary>
        /// Get the connector status
        /// </summary>
        public ConnectorStatus Status { get; private set; }

        /// <summary>
        /// Get the reason status
        /// </summary>
        public String ReasonStatus { get; private set; }

        /// <summary>
        /// Path of discovered connector
        /// </summary>
        private String _connectorModulePath;

        /// <summary>
        /// The loaded manager assenbly
        /// </summary>
        public System.Reflection.Assembly Assembly { get; private set; }

        /// <summary>
        /// The ,anager type
        /// </summary>
        public Type ManagerType { get; private set; }

        /// <summary>
        /// Default constructor :
        /// Load the configuration file and load the connector
        /// </summary>
        /// <param name="connectorModulePath"></param>
        public ConnectorConfiguration(String connectorModulePath)
        {
            _connectorModulePath = connectorModulePath;
            this.CheckConnectorPath();
            if (this.Status == ConnectorStatus.ConnectorPathInavlid | this.Status == ConnectorStatus.PermissionDenied) return;

            this.Init();
        }

        /// <summary>
        /// Init the connector
        /// </summary>
        public void Init()
        {
            String connectorConfigurationFile = System.IO.Path.Combine(_connectorModulePath, CONFIGURATION_FILE);
            this.CheckConnectorConfigurationFilePath(connectorConfigurationFile);
            if (this.Status == ConnectorStatus.MissingConfigurationFile) return;

            //read the configuration file
            try
            {

                var connectorConfig = new System.Configuration.ExeConfigurationFileMap()
                    {
                        ExeConfigFilename = connectorConfigurationFile
                    };

                System.Configuration.Configuration conf = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(connectorConfig, System.Configuration.ConfigurationUserLevel.None);
                String name = conf.AppSettings.Settings["name"].Value;
                this.MainAssembly = conf.AppSettings.Settings["mainAssembly"].Value;
                this.StrongName = conf.AppSettings.Settings["strongName"].Value;

                //Check configuration data
                this.CheckConnectorConfigurationData(name, this.MainAssembly, this.StrongName);
                if (this.Status == ConnectorStatus.MissingMainAssemblyFile | 
                    this.Status == ConnectorStatus.MissingStrongName |
                    this.Status == ConnectorStatus.MissingConnectorName) return;

                this.Name = name;

            }
            catch (Exception ex)
            {
                this.Status = ConnectorStatus.UnknownError;
                this.ReasonStatus = ex.Message;
                return;
            }

            //Check main assembly file
            String assemblyPath = System.IO.Path.Combine(_connectorModulePath, this.MainAssembly);
            if (!System.IO.File.Exists(assemblyPath))
            {
                this.Status = ConnectorStatus.MissingMainAssemblyFile;
                this.ReasonStatus = String.Format("Missing manager main assembly {0}", assemblyPath);
                return;
            }

            //Load the connector assembly to be able to retrieve the manager
            this.LoadAssembly();
            if (this.Status != ConnectorStatus.AssemblyLoaded) return;

            //Get the platform manager type to register it
            this.GetManagerType();

        }

        /// <summary>
        /// Get manager type according its strong name
        /// </summary>
        private void GetManagerType()
        {
            try
            {
                this.ManagerType = Type.GetType(this.StrongName);
                this.Status = ConnectorStatus.TypeResolved;

            }
            catch (Exception ex)
            {
                //Todo add exception management
                this.Status = ConnectorStatus.TypeUnknwon;
                this.ReasonStatus = ex.Message;
            }


        }


        /// <summary>
        /// Load the connector assenbly and get yhe manager type according its strong name
        /// </summary>
        private void LoadAssembly()
        {
            String assemblyPath = System.IO.Path.Combine(_connectorModulePath, this.MainAssembly);
            try
            {
                this.Assembly = System.Reflection.Assembly.LoadFile(assemblyPath);
                this.Status = ConnectorStatus.AssemblyLoaded;

            }
            catch (Exception ex)
            {
                //Todo add exception management
                this.Status = ConnectorStatus.AssemblyLoadFailure;
                this.ReasonStatus = ex.Message;

            }
        }




        /// <summary>
        /// Check connectorPath is valid, exist and is granted to read its content
        /// </summary>
        private void CheckConnectorPath()
        {
            //Check path exists
            if (String.IsNullOrWhiteSpace(_connectorModulePath) && !System.IO.Directory.Exists(_connectorModulePath))
            {
                this.Status = ConnectorStatus.ConnectorPathInavlid;

                //try to set a connector name
                if (String.IsNullOrWhiteSpace(_connectorModulePath))
                {
                    this.Name = "CONNECTOR PATH EMPTY";
                    //Todo add localized message
                    this.ReasonStatus = "The connector path is empty or null";
                }
                else if (!System.IO.Directory.Exists(_connectorModulePath))
                {
                    try
                    {
                        this.Name = System.IO.Path.GetDirectoryName(_connectorModulePath);
                        //Todo add localized message
                        this.ReasonStatus = "The connector path doesn't exist";
                    }
                    catch (Exception ex)
                    {
                        //Todo add exception management
                        this.Name = _connectorModulePath;
                        this.ReasonStatus = ex.Message;
                    }
                }
                //Path is empty or invalid, so quit the check method
                return;
            }

            this.Name = System.IO.Path.GetDirectoryName(_connectorModulePath);

            //Check that path is accessible
            try
            {
                System.IO.Directory.GetDirectories(_connectorModulePath);
                this.Status = ConnectorStatus.Discovered;
            }
            catch (Exception ex)
            {
                //Todo add exception management
                this.Status = ConnectorStatus.PermissionDenied;
                this.ReasonStatus = ex.Message;
            }

        }

        /// <summary>
        /// Check connector configuration file exist
        /// </summary>
        /// <param name="connectorConfigurationFilePath"></param>
        private void CheckConnectorConfigurationFilePath(String connectorConfigurationFilePath)
        {
            if (!System.IO.File.Exists(connectorConfigurationFilePath))
            {
                this.Status = ConnectorStatus.MissingConfigurationFile;
                //todo add localized message
                this.ReasonStatus = String.Format("Missing file {0} in folder {1}", CONFIGURATION_FILE, _connectorModulePath);
            }
        }


        /// <summary>
        /// Check taht connector configuration data is correct
        /// </summary>
        private void CheckConnectorConfigurationData(String name, String mainAssembly, String strongName)
        {

            if (String.IsNullOrEmpty(name))
            {
                this.Status = ConnectorStatus.MissingConnectorName;
                //Todo add localized message
                this.ReasonStatus = "The name is mandatory";
                return;
            }

            if (String.IsNullOrEmpty(this.MainAssembly))
            {
                this.Status = ConnectorStatus.MissingMainAssemblyName;
                //Todo add localized message
                this.ReasonStatus = "The main Assembly file name is mandatory";
                return;
            }

            if (String.IsNullOrEmpty(this.StrongName))
            {
                this.Status = ConnectorStatus.MissingStrongName;
                //Todo add localized message
                this.ReasonStatus = "The manager strong name is mandatory";
                return;
            }

        }

    }
}
